Circular buffers are commonly used in many Digital Signal Processing (DSP) filters and other similar algorithms and applications. The most common DSP operation is the implementation of a filter function which achieves in the digital domain what an analog filter would achieve in the analog domain. Since digital values are discrete, the filter operation attempts to emulate the operation of the analog filter using a method in which a number “n” of input values are used at each computation step. Although discontinuity in signal values does not occur in the analog domain, such discontinuity can occur in discrete digital computations. In an attempt to mitigate the negative effects of the discontinuity in signal values, each filter summation uses one new sample value and n−1 old sample values. This type of filter operation is best done using a circular buffer which simply adds the new value to the current position in the buffer and reuses all the old values without re-copying them to a new buffer. And this type of filter computation is so common that substantially all digital signal processors provide support for hardware circular buffers. Otherwise, the overhead of copying n−1 values for each outer loop of the filter summation would almost always be necessary, which would significantly reduce efficiency and performance.
Conventional DSP and DSP-like microprocessors provided support for circular buffers. Such conventional implementations, however, often had many limitations and deficiencies and were often difficult to implement and/or use. For example, multiple and/or new states were often required. The number of buffers that could be simultaneously defined and used was often constrained by the total number of special purpose register sets that were implemented to hold the register values and variables. In typical conventional microprocessor applications, each circular buffer was implemented using multiple registers that held the location of the buffer base address and buffer limit. Each set of buffer registers typically comprised special purpose registers, rather than general purpose registers, where each set was often dedicated to a single buffer. Thus, multiple sets were required to support multiple circular buffers implemented at the same time resulting in an artificial limit of simultaneous buffers. If more buffers had to be used simultaneously than the total number of available buffer register sets, then one or more buffer states had to be stored and retrieved, significantly reducing efficiency. Furthermore, in many conventional configurations, circular buffers were implemented using circular or modular address arithmetic to recalculate the next address in the circular buffer. Such arithmetic solutions typically required storage of the buffer size, complicated the implementation source code, and resulted in less efficient code that consumed valuable processor cycles during run-time.
In many of the conventional configurations including the arithmetic solutions described above, the buffer size was often limited to a power of two so that the buffer size could be represented as an exponent. The “exponent of two” buffer size representation often resulted in significant waste of memory resources. For example, if a buffer size of 10 kilobytes (KB) was required, the buffer size had to be 16 KB since the next smaller buffer size of 8 KB was not adequate. Furthermore, conventional configurations including the arithmetic solutions required stricter limits on the location of the buffer, such as alignment with the data size of the memory.
It is desired to enable implementation of circular buffers in program memory of a microprocessor system that allows maximum flexibility with minimal constraints. It is further desired to maximize compiled code efficiency and performance.